home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / du.arc / DU.C next >
C/C++ Source or Header  |  1990-10-05  |  8KB  |  305 lines

  1. /* @(#) du.c 1.2 90/09/08 14:38:52 */
  2.  
  3. /*
  4.  * Package:    du - Enhanced "du" disk usage report generator.
  5.  * File:    du.c - Main program.
  6.  *
  7.  * Sat Sep  8 14:34:56 1990 - Chip Rosenthal <chip@chinacat.Unicom.COM>
  8.  *    Cleanup for distribution.
  9.  * Tue Apr 17 21:50:58 1990 - Chip Rosenthal <chip@chinacat.Unicom.COM>
  10.  *    Original composition.
  11.  *
  12.  * Copyright 1990, Unicom Systems Development.  All rights reserved.
  13.  * See accompanying README file for terms of distribution and use.
  14.  */
  15.  
  16. #include <stdio.h>
  17. #define INTERN
  18. #include "du.h"
  19. #include "patchlevel.h"
  20.  
  21. static char Copyright[] =
  22.     "@(#) Copyright 1990, Unicom Systems Development.  All rights reserved.";
  23. static char SccsID[] = "@(#) du.c 1.2 90/09/08 14:38:52";
  24.  
  25. #define USAGE    "usage: %s [ options ] [ path ... ]    (try '-h' for help)\n"
  26.  
  27. /*
  28.  * Local procedures.
  29.  */
  30. static void do_help();
  31. static void set_breakdown();
  32.  
  33. /*
  34.  * External procedures.
  35.  */
  36. extern char *getcwd();
  37. extern char *strtok();
  38. extern long time();
  39. extern void *malloc();
  40. extern void exit();
  41.  
  42.  
  43. main(argc,argv)
  44. int argc;
  45. char *argv[];
  46. {
  47.     int i;
  48.     extern char *optarg;
  49.     extern int optind;
  50.  
  51.     /*
  52.      * Initialize.
  53.      */
  54.     Progname        =argv[0];
  55.     Accum_subdirs    =TRUE;    /* add usage of a subdir into parent's usage  */
  56.     All_entries        =FALSE;    /* just show directories              */
  57.     Cross_filesys    =TRUE;    /* continue down dirs across filesystems      */
  58.     Descend_dirs    =TRUE;    /* follow directories recursively          */
  59.     Suppress_repeats    =TRUE;    /* report multiply linked files only once     */
  60. #ifdef PRINT_ERRORS
  61.     Print_errors    =TRUE;    /* enable error messages              */
  62. #else
  63.     Print_errors    =FALSE;    /* suppress error messages              */
  64. #endif
  65.     Skip_links        =FALSE;    /* allow checking of multiply-linked files    */
  66.     Total_only        =FALSE;    /* print usage at each directory encountered  */
  67.     Report_blksize    =REPORT_BLKSIZE; /* block size used in reports          */
  68.     Num_break        =1;    /* only present on column in the usage report */
  69.     Breakdown[0]    =0;    /* that col should include all existing files */
  70.  
  71.     /* 
  72.      * Crack command line options.
  73.      */
  74.     while ( (i=getopt(argc, argv, "ab:c:dfhilrsu")) != EOF ) {
  75.     switch ( i ) {
  76.         case 'a':    All_entries = TRUE;            break;
  77.         case 'b':   Report_blksize = atoi(optarg);        break;
  78.         case 'c':    set_breakdown(optarg);            break;
  79.         case 'd':    Descend_dirs = FALSE;            break;
  80.         case 'f':    Cross_filesys = FALSE;            break;
  81.         case 'h':    do_help();                exit(0);
  82.         case 'i':    Accum_subdirs = FALSE;            break;
  83.         case 'l':    Suppress_repeats = FALSE;        break;
  84.         case 'r':    Print_errors = TRUE;            break;
  85.         case 's':    Total_only = TRUE;            break;
  86.         case 'u':    Skip_links = TRUE;            break;
  87.         default:    fprintf(stderr, USAGE, Progname);    exit(1);
  88.     }
  89.     }
  90.  
  91.     /*
  92.      * Initialize the filesystem information tables.
  93.      */
  94.     fs_initinfo();
  95.  
  96.     /*
  97.      * Get the starting directory in case we need to chdir.
  98.      */
  99.     if ( (Curr_dir=getcwd((char *)NULL, 256)) == NULL )
  100.     errmssg(ERR_ABORT,"couldn't get current working directory");
  101.  
  102.     /*
  103.      * Get the time so we can do the breakdown of usage by age.
  104.      */
  105.     (void) time(&Curr_time);
  106.  
  107.     /*
  108.      * If no arguments specified on the command line then do the current dir.
  109.      */
  110.     if ( optind == argc ) {
  111.     du_entry(".");
  112.     exit(0);
  113.     }
  114.  
  115.     /*
  116.      * Do all the items given on the command line.
  117.      */
  118.     for ( i = optind ; i < argc ; ++i )
  119.     du_entry(argv[i]);
  120.     exit(0);
  121.  
  122.     /*NOTREACHED*/
  123. }
  124.  
  125.  
  126. static char *usage_text[] = {
  127.     "",
  128.     "du - version %V (patchlevel %L)",
  129.     "",
  130.     "  Usage:  %P [ options ] [ path ... ]",
  131.     "",
  132.     "  Options:",
  133.     "    -a          Report all files encountered, not just directories.",
  134.     "    -b n        Report as if disk blocks were 'n' bytes (default %B).",
  135.     "                  (A '0' value reports in native filesystem block size.)",
  136.     "    -c n,n,...  Breakdown by age, one col for each 'n' days or older.",
  137.     "    -d          Do not descend into directories encountered.",
  138.     "    -f          Do cross filesystems.",
  139.     "    -h          Display this help message.",
  140.     "    -i          Do not accumulate subdirectories' usage into parent dir.",
  141.     "    -l          Count multiply linked files each time encountered.",
  142. #ifndef PRINT_ERRORS
  143.     "    -r          Print (don't suppress) errors which occur during scan.",
  144. #endif
  145.     "    -s          Only print a total for each argument on the command line.",
  146.     "    -u          Skip (do not count) multiply linked files entirely.",
  147.     "",
  148.     "Copyright 1990, Unicom Systems Development.  All rights reserved.",
  149.     "See distributed README file for terms of distribution and use.",
  150.     "",
  151.     NULL
  152. };
  153.  
  154.  
  155. static void do_help()
  156. {
  157.     Reg char *s, **linep;
  158.  
  159.     for ( linep = usage_text ; *linep != NULL ; ++linep ) {
  160.     for ( s = *linep ; *s != '\0' ; ++s ) {
  161.         if ( *s == '%' ) {
  162.         switch ( *++s ) {
  163.             case 'B': fprintf(stderr,"%d",REPORT_BLKSIZE);    break;
  164.             case 'P': fputs(Progname,stderr);            break;
  165.             case 'V': fputs(VERSION,stderr);            break;
  166.             case 'L': fprintf(stderr,"%d",PATCHLEVEL);        break;
  167.             default:  putc('%',stderr); putc(*s,stderr);    break;
  168.         }
  169.         } else {
  170.         putc(*s,stderr);
  171.         }
  172.     }
  173.     putc('\n', stderr);
  174.     }
  175.     exit(0);
  176. }
  177.  
  178.  
  179. static void set_breakdown(str)
  180. char *str;
  181. {
  182.     char *s;
  183.  
  184.     Num_break = 0;
  185.     while ( (s=strtok(str, " \t,")) != NULL ) {
  186.     if ( Num_break >= MAX_BREAK ) {
  187.         fprintf(stderr, "%s: too many breakdown catagories\n", Progname);
  188.         exit(1);
  189.     }
  190.     if ( (Breakdown[Num_break++]=atoi(s)) == 0 && *s != '0' ) {
  191.         fprintf(stderr, "%s: bad breakdown value '%s'\n", Progname, s);
  192.         exit(1);
  193.     }
  194.     str = NULL;
  195.     }
  196.  
  197.     if ( Num_break == 0 ) {
  198.     fprintf(stderr, "%s: no breakdown catagories specified\n", Progname);
  199.     exit(1);
  200.     }
  201.  
  202. }
  203.  
  204.  
  205. void *xmalloc(n)
  206. unsigned n;
  207. {
  208.     char *s;
  209.     if ( (s=malloc(n)) == NULL ) {
  210.     fputs("malloc: out of space\n",stderr);
  211.     exit(1);
  212.     }
  213.     return s;
  214. }
  215.  
  216.  
  217. /*
  218.  * Error Message Interface - The errmssg() routine uses a printf-like syntax
  219.  * to display an error message.  If "errno" is nonzero, it will be included
  220.  * in the diagnostic message.
  221.  */
  222.  
  223. #include <varargs.h>
  224.  
  225. /*VARARGS1*/
  226. void errmssg(severity, fmt, va_alist)
  227. int severity;
  228. char *fmt;
  229. va_dcl
  230. {
  231.     va_list args;
  232.     int save_errno;
  233.     extern int errno;
  234.     extern char *sys_errlist[];
  235.  
  236.     if ( !Print_errors && severity < ERR_ABORT )
  237.     return;
  238.  
  239.     save_errno = errno;
  240.     va_start(args);
  241.     fprintf(stderr, "%s: ", Progname);
  242.     vfprintf(stderr, fmt, args);
  243.     if ( save_errno > 0 )
  244.     fprintf(stderr, " (%s)", sys_errlist[save_errno]);
  245.     putc('\n',stderr);
  246.     va_end(args);
  247.  
  248.     if ( severity >= ERR_ABORT )
  249.     exit(1);
  250. }
  251.  
  252.  
  253. /*
  254.  * Disk Usage Functions - Disk usage is stored in a (struct dskusage) datatype.
  255.  * The following routines provide all the required manipulations of this
  256.  * datatype, and no knowledge of the internals of this structure exists
  257.  * outside these routines.  The following functions are provided:
  258.  *
  259.  *   set_usage() - Load a (struct dskusage) from file information.
  260.  *   add_usage() - Accumulate data from one (struct dskusage) into another.
  261.  *   print_usage() - Print statistics from a (struct dskusage).
  262.  */
  263.  
  264. #include <sys/types.h>
  265. #include <sys/stat.h>
  266.  
  267. void set_usage(usage, sbufp, nblocks)
  268. Reg struct dskusage *usage;
  269. struct stat *sbufp;
  270. Reg long nblocks;
  271. {
  272.     Reg int i;
  273.     long ndays;
  274.  
  275.      /*
  276.       * The following luckily works out OK.  If a file is created after "du"
  277.       * is started, the "Curr_time-sbufp->st_mtime" value will be a small
  278.       * negative number, however when divided by "60*60*24" it will truncate
  279.       * to zero, so it will be counted in the breakdown OK.
  280.       */
  281.     ndays = (Curr_time - sbufp->st_mtime) / ( 60*60*24 /* sec per day */ );
  282.  
  283.     for ( i = Num_break-1 ; i >= 0 ; --i )
  284.     usage->b[i] = ( Breakdown[i] <= ndays ? nblocks : 0L );
  285. }
  286.  
  287. void add_usage(tot_usage, ent_usage)
  288. Reg struct dskusage *tot_usage, *ent_usage;
  289. {
  290.     Reg int i;
  291.     for ( i = 0 ; i < Num_break ; ++i )
  292.     tot_usage->b[i] += ent_usage->b[i];
  293. }
  294.  
  295. void print_usage(name, usage)
  296. char *name;
  297. struct dskusage *usage;
  298. {
  299.     int i;
  300.     for ( i = 0 ; i < Num_break ; ++i )
  301.     printf("%ld\t", usage->b[i]);
  302.     printf("%s\n", name);
  303. }
  304.  
  305.